﻿using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Windows.ApplicationModel.Resources.Core;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using System.Collections.Specialized;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Threading.Tasks;
using Windows.System;
using Windows.UI.Xaml;

// Le modèle de données défini par ce fichier sert d'exemple représentatif d'un modèle fortement typé
// prenant en charge les notifications lorsque les membres sont ajoutés, supprimés ou modifiés. Les noms
// de propriétés choisis correspondent aux liaisons de données dans les modèles d'élément standard.
//
// Les applications peuvent utiliser ce modèle comme point de départ et le modifier à leur convenance, ou le supprimer complètement et
// le remplacer par un autre correspondant à leurs besoins.

namespace MyVideoManager.Data
{
    /// <summary>
    /// Classe de base pour <see cref="SampleDataItem"/> et <see cref="SampleDataGroup"/> qui
    /// définit les propriétés communes au deux.
    /// </summary>
    [Windows.Foundation.Metadata.WebHostHidden]
    public abstract class SampleDataCommon : MyVideoManager.Common.BindableBase
    {
        private static Uri _baseUri = new Uri("ms-appx:///");

        public SampleDataCommon(String uniqueId, String title, String subtitle, String imagePath, String description)
        {
            this._uniqueId = uniqueId;
            this._title = title;
            this._subtitle = subtitle;
            this._description = description;
            this._imagePath = imagePath;
        }

        private string _uniqueId = string.Empty;
        public string UniqueId
        {
            get { return this._uniqueId; }
            set { this.SetProperty(ref this._uniqueId, value); }
        }

        private string _title = string.Empty;
        public string Title
        {
            get { return this._title; }
            set { this.SetProperty(ref this._title, value); }
        }

        private string _subtitle = string.Empty;
        public string Subtitle
        {
            get { return this._subtitle; }
            set { this.SetProperty(ref this._subtitle, value); }
        }

        private string _description = string.Empty;
        public string Description
        {
            get { return this._description; }
            set { this.SetProperty(ref this._description, value); }
        }

        private ImageSource _image = null;
        private String _imagePath = null;
        public ImageSource Image
        {
            get
            {
                if (this._image == null && this._imagePath != null)
                {
                    this._image = new BitmapImage(new Uri(SampleDataCommon._baseUri, this._imagePath));
                }
                return this._image;
            }

            set
            {
                this._imagePath = null;
                this.SetProperty(ref this._image, value);
            }
        }

        public void SetImage(String path)
        {
            this._image = null;
            this._imagePath = path;
            this.OnPropertyChanged("Image");
        }

        public override string ToString()
        {
            return this.Title;
        }
    }

    /// <summary>
    /// Modèle de données d'élément générique.
    /// </summary>
    public class SampleDataItem : SampleDataCommon
    {
        public SampleDataItem(String uniqueId, String title, String subtitle, String originalTitle, String actors, String date, String imagePath, String description, String content, SampleDataGroup group)
            : base(uniqueId, title, subtitle, imagePath, description)
        {
            this._content = content;
            this._group = group;
            this._originalTitle = originalTitle;
            this._actors = actors;
            this._date = date;
        }

        private string _content = string.Empty;
        public string Content
        {
            get { return this._content; }
            set { this.SetProperty(ref this._content, value); }
        }

        private SampleDataGroup _group;
        public SampleDataGroup Group
        {
            get { return this._group; }
            set { this.SetProperty(ref this._group, value); }
        }
        private string _originalTitle = string.Empty;
        public string OriginalTitle
        {
            get { return this._originalTitle; }
            set { this.SetProperty(ref this._originalTitle, value); }
        }

        private string _actors = string.Empty;
        public string Actors
        {
            get { return this._actors; }
            set { this.SetProperty(ref this._actors, value); }
        }

        private string _date = string.Empty;
        public string Date
        {
            get { return this._date; }
            set { this.SetProperty(ref this._date, value); }
        }
    }

    /// <summary>
    /// Modèle de données de groupe générique.
    /// </summary>
    public class SampleDataGroup : SampleDataCommon
    {
        public SampleDataGroup(String uniqueId, String title, String subtitle, String imagePath, String description)
            : base(uniqueId, title, subtitle, imagePath, description)
        {
            Items.CollectionChanged += ItemsCollectionChanged;
        }

        private void ItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            // Fournit un sous-ensemble de la collection complète d'éléments avec laquelle effectuer une liaison à partir d'un GroupedItemsPage
            // pour deux raisons : GridView ne virtualise pas les collections d'éléments volumineuses, et
            // améliore l'expérience utilisateur lors de la navigation dans des groupes contenant un nombre important
            // d'éléments.
            //
            // 12 éléments maximum sont affichés, car cela se traduit par des colonnes de grille remplies,
            // qu'il y ait 1, 2, 3, 4 ou 6 lignes affichées

            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    if (e.NewStartingIndex < 12)
                    {
                        TopItems.Insert(e.NewStartingIndex,Items[e.NewStartingIndex]);
                        if (TopItems.Count > 12)
                        {
                            TopItems.RemoveAt(12);
                        }
                    }
                    break;
                case NotifyCollectionChangedAction.Move:
                    if (e.OldStartingIndex < 12 && e.NewStartingIndex < 12)
                    {
                        TopItems.Move(e.OldStartingIndex, e.NewStartingIndex);
                    }
                    else if (e.OldStartingIndex < 12)
                    {
                        TopItems.RemoveAt(e.OldStartingIndex);
                        TopItems.Add(Items[11]);
                    }
                    else if (e.NewStartingIndex < 12)
                    {
                        TopItems.Insert(e.NewStartingIndex, Items[e.NewStartingIndex]);
                        TopItems.RemoveAt(12);
                    }
                    break;
                case NotifyCollectionChangedAction.Remove:
                    if (e.OldStartingIndex < 12)
                    {
                        TopItems.RemoveAt(e.OldStartingIndex);
                        if (Items.Count >= 12)
                        {
                            TopItems.Add(Items[11]);
                        }
                    }
                    break;
                case NotifyCollectionChangedAction.Replace:
                    if (e.OldStartingIndex < 12)
                    {
                        TopItems[e.OldStartingIndex] = Items[e.OldStartingIndex];
                    }
                    break;
                case NotifyCollectionChangedAction.Reset:
                    TopItems.Clear();
                    while (TopItems.Count < Items.Count && TopItems.Count < 12)
                    {
                        TopItems.Add(Items[TopItems.Count]);
                    }
                    break;
            }
        }

        private ObservableCollection<SampleDataItem> _items = new ObservableCollection<SampleDataItem>();
        public ObservableCollection<SampleDataItem> Items
        {
            get { return this._items; }
        }

        private ObservableCollection<SampleDataItem> _topItem = new ObservableCollection<SampleDataItem>();
        public ObservableCollection<SampleDataItem> TopItems
        {
            get {return this._topItem; }
        }
    }

    /// <summary>
    /// Crée une collection de groupes et d'éléments dont le contenu est codé en dur.
    /// 
    /// SampleDataSource initialise avec les données des espaces réservés plutôt que les données de production
    /// actives, afin que les exemples de données soient fournis à la fois au moment de la conception et de l'exécution.
    /// </summary>
    public sealed class SampleDataSource
    {
        private static SampleDataSource _sampleDataSource = new SampleDataSource();

        private ObservableCollection<SampleDataGroup> _allGroups = new ObservableCollection<SampleDataGroup>();
        public ObservableCollection<SampleDataGroup> AllGroups
        {
            get { return this._allGroups; }
        }

        public static IEnumerable<SampleDataGroup> GetGroups(string uniqueId)
        {
            if (!uniqueId.Equals("AllGroups")) throw new ArgumentException("Only 'AllGroups' is supported as a collection of groups");
            
            return _sampleDataSource.AllGroups;
        }

        public static SampleDataGroup GetGroup(string uniqueId)
        {
            // Une simple recherche linéaire est acceptable pour les petits groupes de données
            var matches = _sampleDataSource.AllGroups.Where((group) => group.UniqueId.Equals(uniqueId));
            if (matches.Count() == 1) return matches.First();
            return null;
        }

        public static SampleDataItem GetItem(string uniqueId)
        {
            // Une simple recherche linéaire est acceptable pour les petits groupes de données
            var matches = _sampleDataSource.AllGroups.SelectMany(group => group.Items).Where((item) => item.UniqueId.Equals(uniqueId));
            if (matches.Count() == 1) return matches.First();
            return null;
        }



        /* Methode d'ajout de films par leurs code
         * ajouter une adresse xml dans 'liens'en changeant le code du film
         * pour trouver le code du film : http://api.allocine.fr/rest/v3/search?partner=YW5kcm9pZC12M3M&filter=movie&count=5&page=1&q=avatar&format=xml
         * changer le parametre q= par le nom du film
         * trouvez la ligne <movie code="XXXXX">*/
        public async void ForgeBaseLink(String[] xml_links, SampleDataGroup group)
        {
            group.Items.Clear();
            foreach (String link in xml_links)
            {
                Uri uri = new Uri(link);

                Windows.Data.Xml.Dom.XmlDocument doc = await Windows.Data.Xml.Dom.XmlDocument.LoadFromUriAsync(uri);
                group.Items.Add(new SampleDataItem(doc.GetElementsByTagName("movie").Item(0).Attributes.GetNamedItem("code").InnerText,
                        doc.GetElementsByTagName("title").Item(0).InnerText,
                        String.Format("Acteurs : {0}", doc.GetElementsByTagName("actors").Item(0).InnerText),
                        String.Format("Titre Original : {0}",doc.GetElementsByTagName("originalTitle").Item(0).InnerText),
                        String.Format("Acteurs : {0}",doc.GetElementsByTagName("actors").Item(0).InnerText),
                        String.Format("Date de sortie : {0}",doc.GetElementsByTagName("releaseDate").Item(0).InnerText),
                        doc.GetElementsByTagName("poster").Item(0).Attributes.GetNamedItem("href").InnerText,
                        doc.GetElementsByTagName("synopsisShort").Item(0).InnerText,
                        doc.GetElementsByTagName("synopsis").Item(0).InnerText,
                        group));
                group.SetImage(doc.GetElementsByTagName("poster").Item(0).Attributes.GetNamedItem("href").InnerText);
            }
        }
        /* Methode d'ajout de films par ajout du fichier XML dans le dossier XML
         * Cette methode liste les fichiers du dossier et les traduit
         * la methode vérifie que le fichier est au format xml et qu'il est bien formé
         * */
        public async void ForgedBaseLocal(String local_folder_links, SampleDataGroup group)
        {
            // Ne pas oublier de charger le fichier xml dans la solution pour pouvoir le voir dans la liste
            Windows.Storage.StorageFolder storageFolder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync(local_folder_links);
            Windows.Data.Xml.Dom.XmlLoadSettings loadSettings = new Windows.Data.Xml.Dom.XmlLoadSettings();
            loadSettings.ProhibitDtd = false;
            loadSettings.ResolveExternals = false;
            IReadOnlyList<Windows.Storage.StorageFile> File_List = await storageFolder.GetFilesAsync();
            group.Items.Clear();
            foreach(var File in File_List)            
            {
                Windows.Storage.StorageFile storageFile = await storageFolder.GetFileAsync(File.Name);
                Windows.Data.Xml.Dom.XmlDocument doc = await Windows.Data.Xml.Dom.XmlDocument.LoadFromFileAsync(storageFile, loadSettings);
                group.Items.Add(new SampleDataItem(doc.GetElementsByTagName("movie").Item(0).Attributes.GetNamedItem("code").InnerText,
                        doc.GetElementsByTagName("title").Item(0).InnerText,
                        String.Format("Acteurs : {0}", doc.GetElementsByTagName("actors").Item(0).InnerText),
                        String.Format("Titre Original : {0}", doc.GetElementsByTagName("originalTitle").Item(0).InnerText),
                        String.Format("Acteurs : {0}", doc.GetElementsByTagName("actors").Item(0).InnerText),
                        String.Format("Date de sortie : {0}", doc.GetElementsByTagName("releaseDate").Item(0).InnerText),
                        doc.GetElementsByTagName("poster").Item(0).Attributes.GetNamedItem("href").InnerText,
                        doc.GetElementsByTagName("synopsisShort").Item(0).InnerText,
                        doc.GetElementsByTagName("synopsis").Item(0).InnerText,
                        group));
                group.SetImage(doc.GetElementsByTagName("poster").Item(0).Attributes.GetNamedItem("href").InnerText);
            }
        }
        
        public SampleDataSource()
        {
            var group1 = new SampleDataGroup("Group-1",
                    "Local",
                    "Fiches enregistrées dans le dossier XML",
                    "Assets/DarkGray.png",
                    "Films en local");
            group1.Items.Add(new SampleDataItem("Group-1-Item-1",
                   "N/A",
                   String.Format("Acteurs : {0}", "N/A"),
                   String.Format("Titre Original : {0}", "N/A"),
                   String.Format("Acteurs : {0}", "N/A"),
                   String.Format("Date de sortie : {0}", "N/A"),
                   "Assets/LightGray.png",
                   "N/A",
                   "N/A",
                   group1));
            this.AllGroups.Add(group1);
            
            var group2 = new SampleDataGroup("Group-2",
                       "Films Allocine",
                       "Fiches en ligne",
                       "Assets/LightGray.png",
                       "Films ajoutés via l'API d'allocine");
             group2.Items.Add(new SampleDataItem("Group-2-Item-1",
                   "N/A",
                   String.Format("Acteurs : {0}", "N/A"),
                   String.Format("Titre Original : {0}", "N/A"),
                   String.Format("Acteurs : {0}", "N/A"),
                   String.Format("Date de sortie : {0}", "N/A"),
                   "Assets/LightGray.png",
                   "N/A",
                   "N/A",
                   group2));
            this.AllGroups.Add(group2);

            var group4 = new SampleDataGroup("Group-4",
                       "Films Allocine",
                       "Fiches en ligne",
                       "Assets/LightGray.png",
                       "Films ajoutés via l'API d'allocine");
            group4.Items.Add(new SampleDataItem("Group-4-Item-1",
                  "N/A",
                  String.Format("Acteurs : {0}", "N/A"),
                  String.Format("Titre Original : {0}", "N/A"),
                  String.Format("Acteurs : {0}", "N/A"),
                  String.Format("Date de sortie : {0}", "N/A"),
                  "Assets/LightGray.png",
                  "N/A",
                  "N/A",
                  group4));
            this.AllGroups.Add(group4);

            var group3 = new SampleDataGroup("Group-3",
                       "Films Allocine",
                       "Fiches en ligne",
                       "Assets/LightGray.png",
                       "Films ajoutés via l'API d'allocine");
            group3.Items.Add(new SampleDataItem("Group-3-Item-1",
                  "N/A",
                  String.Format("Acteurs : {0}", "N/A"),
                  String.Format("Titre Original : {0}", "N/A"),
                  String.Format("Acteurs : {0}", "N/A"),
                  String.Format("Date de sortie : {0}", "N/A"),
                  "Assets/LightGray.png",
                  "N/A",
                  "N/A",
                  group3));
            this.AllGroups.Add(group3);
            /*
            String[] liens_groupe2 = new String[]{
                "http://api.allocine.fr/rest/v3/movie?partner=YW5kcm9pZC12M3M&code=61282&profile=medium&format=xml",
                "http://api.allocine.fr/rest/v3/movie?partner=YW5kcm9pZC12M3M&code=3996&profile=medium&format=xml",
                "http://api.allocine.fr/rest/v3/movie?partner=YW5kcm9pZC12M3M&code=29233&profile=medium&format=xml",
                "http://api.allocine.fr/rest/v3/movie?partner=YW5kcm9pZC12M3M&code=130440&profile=medium&format=xml",
                "http://api.allocine.fr/rest/v3/movie?partner=YW5kcm9pZC12M3M&code=53751&profile=medium&format=xml",
                "http://api.allocine.fr/rest/v3/movie?partner=YW5kcm9pZC12M3M&code=136190&profile=medium&format=xml",
                "http://api.allocine.fr/rest/v3/movie?partner=YW5kcm9pZC12M3M&code=139589&profile=medium&format=xml"};
            String liens_groupe1 = "XML"; // nom du dossier ou se trouvent les fichiers xml
            //enregistrer le fichiers xml depuis son adresse http://api.allocine.fr/rest/v3/...

            ForgeBaseLink(liens_groupe2, group2);
            ForgeBaseLink(liens_groupe2, group3);
            ForgeBaseLink(liens_groupe2, group4);
            ForgedBaseLocal(liens_groupe1, group1);*/
        }

    }
}
